<template lang="pug">
q-select(
  :loading="!loaded"
  :options="currentOptions"
  :use-input="filterable"
  emit-value
  map-options
  @filter="filterFn"
  @virtual-scroll="onVirtualScroll"
  v-model="value"
)
</template>

<script setup>
import {computed, ref, nextTick, watch} from "vue";

const props = defineProps({
  options: {
    type: Array,
    default: () => []
  },
  modelValue: {
    type: String,
    default: null
  },
  // 可以过滤
  filterable: {
    type: Boolean,
    default: false
  },
  // 虚拟滚动
  virtualSelect: {
    type: Boolean,
    default: false
  },
  filterFunction: {
    type: Function,
    default: (options) => options,
  }
})


const loaded = computed(() => {
  return props.options.length > 0
})

const value = computed({
  get: () => props.modelValue,
  set: (val) => emit('update:modelValue', val)
})

const allOptions = ref(props.options)

const filterFn = (val, update) => {
  if (val === '') {
    update(() => {
      allOptions.value = props.options
      allOptions.value = props.filterFunction(allOptions.value)
      return currentOptions.value
    })
    return
  }
  const needle = val.toLowerCase()
  allOptions.value = props.options.filter(v => v.label.toLowerCase().indexOf(needle) > -1 || v.value.toLowerCase().indexOf(needle) > -1)
  allOptions.value = props.filterFunction(allOptions.value)
  update(() => {
    return currentOptions.value
  })
}


const emit = defineEmits(['update:modelValue'])
const loading = ref(false)
const nextPage = ref(2)
const pageSize = ref(20)

const currentOptions = computed(() => {
  if (!props.virtualSelect) {
    return allOptions.value
  }
  // 如果modelValue没有值
  if (!props.modelValue) {
    return allOptions.value.slice(0, pageSize.value * (nextPage.value - 1))
  }
  let curOptions = allOptions.value.slice(0, pageSize.value * (nextPage.value - 1))
  // 如果modelValue是字符串
  if (typeof value.value == 'string') {
    if (curOptions.filter(item => item.value == value.value).length == 0) curOptions.push(...allOptions.value.filter(item => item.value == value.value))
    return curOptions
  }
  for (let i = 0; i < value.value.length; i++) {
    const item_i = value.value[i]
    if (curOptions.filter(item => item.value == item_i).length == 0) curOptions.push(...allOptions.value.filter(item => item.value == item_i))
  }
  return curOptions
})


const lastPage = computed(() => {
  return Math.ceil(allOptions.value.length / pageSize.value) + 1
})

const onVirtualScroll = ({to, ref}) => {
  if (!props.virtualSelect) return
  const lastIndex = currentOptions.value.length - 1
  if (loading.value !== true && nextPage.value < lastPage.value && to === lastIndex) {
    loading.value = true
    setTimeout(() => {
      nextPage.value++
      nextTick(() => {
        ref.refresh()
        loading.value = false
      })
    }, 100)
  }
}

watch(() => props.options, () => {
  allOptions.value = props.options
}, {deep: true})


</script>

<style scoped>

</style>